﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;

namespace NGE
{
    internal class Xinput
    {
        public Xinput(Game g)
        {
            game = g;
            Connect();
        }

        Game game;
        int ks;
        public void Heartbeat()
        {
            _XINPUT_STATE xs;
            XInputGetState(0, out xs);

            if (xs.Gamepad.wButtons > 0)
            {
                for (int b = 0; b < 16; b++)
                {
                    int v = (1 << b);
                    if ((v & xs.Gamepad.wButtons) == 0)
                    {

                    }
                    else
                    {
                        if ((v & ks) == 0)
                        {
                            for (int i = 0; i < game.Components.Count; i++)
                            {
                                game.Components[i].NotifyGamepadEvent(0, xs.Gamepad.wButtons, GamepadState.ButtonDown);
                            }
                            ks |= v;
                        }
                        else
                        {
                            for (int i = 0; i < game.Components.Count; i++)
                            {
                                game.Components[i].NotifyGamepadEvent(0, xs.Gamepad.wButtons, GamepadState.ButtonHold);
                            }
                        }
                    }
                }
            }
            else
            {
                for (int b = 0; b < 16; b++)
                {
                    int v = (1 << b);
                    if ((v & xs.Gamepad.wButtons) == 0)
                    {
                        if ((v & ks) == 0)
                        {

                        }
                        else
                        {
                            for (int i = 0; i < game.Components.Count; i++)
                            {
                                game.Components[i].NotifyGamepadEvent(0, xs.Gamepad.wButtons, GamepadState.ButtonUp);
                            }
                            ks &= ~v;
                        }
                    }
                }
            }
        }

        public void Connect()
        {
            _XINPUT_CAPABILITIES xc;
            XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, out xc);
            _XINPUT_BATTERY_INFORMATION xbi;
            XInputGetBatteryInformation(0, XINPUT_DEVTYPE_GAMEPAD, out xbi);
            _XINPUT_KEYSTROKE xk;
            XInputGetKeystroke(0, 0, out xk);
        }

        #region define
        /***************************************************************************
        *                                                                          *
        *   XInput.h -- This module defines XBOX controller APIs                   *
        *               and constansts for the Windows platform.                   *
        *                                                                          *
        *   Copyright (c) Microsoft Corp. All rights reserved.                     *
        *                                                                          *
        ***************************************************************************/

        // Current name of the DLL shipped in the same SDK as this header.
        // The name reflects the current version
        //
        // Device types available in XINPUT_CAPABILITIES
        //
        public const int XINPUT_DEVTYPE_GAMEPAD = 0x01;

        //
        // Device subtypes available in XINPUT_CAPABILITIES
        //
        public const int XINPUT_DEVSUBTYPE_GAMEPAD = 0x01;


        public const int XINPUT_DEVSUBTYPE_WHEEL = 0x02;
        public const int XINPUT_DEVSUBTYPE_ARCADE_STICK = 0x03;
        public const int XINPUT_DEVSUBTYPE_FLIGHT_SICK = 0x04;
        public const int XINPUT_DEVSUBTYPE_DANCE_PAD = 0x05;
        public const int XINPUT_DEVSUBTYPE_GUITAR = 0x06;
        public const int XINPUT_DEVSUBTYPE_DRUM_KIT = 0x08;


        //
        // Flags for XINPUT_CAPABILITIES
        //
        public const int XINPUT_CAPS_VOICE_SUPPORTED = 0x0004;

        //
        // Constants for gamepad buttons
        //
        public const int XINPUT_GAMEPAD_DPAD_UP = 0x0001;
        public const int XINPUT_GAMEPAD_DPAD_DOWN = 0x0002;
        public const int XINPUT_GAMEPAD_DPAD_LEFT = 0x0004;
        public const int XINPUT_GAMEPAD_DPAD_RIGHT = 0x0008;
        public const int XINPUT_GAMEPAD_START = 0x0010;
        public const int XINPUT_GAMEPAD_BACK = 0x0020;
        public const int XINPUT_GAMEPAD_LEFT_THUMB = 0x0040;
        public const int XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080;
        public const int XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100;
        public const int XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200;
        public const int XINPUT_GAMEPAD_A = 0x1000;
        public const int XINPUT_GAMEPAD_B = 0x2000;
        public const int XINPUT_GAMEPAD_X = 0x4000;
        public const int XINPUT_GAMEPAD_Y = 0x8000;

        //
        // Gamepad thresholds
        //
        public const int XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 10000;
        public const int XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE = 10000;
        public const int XINPUT_GAMEPAD_TRIGGER_THRESHOLD = 30;

        //
        // Flags to pass to XInputGetCapabilities
        //
        public const int XINPUT_FLAG_GAMEPAD = 0x00000001;

        //
        // Devices that support batteries
        //
        public const int BATTERY_DEVTYPE_GAMEPAD = 0x00;
        public const int BATTERY_DEVTYPE_HEADSET = 0x01;

        //
        // Flags for battery status level
        //
        public const int BATTERY_TYPE_DISCONNECTED = 0x00;  // This device is not connected
        public const int BATTERY_TYPE_WIRED = 0x01;  // Wired device, no battery
        public const int BATTERY_TYPE_ALKALINE = 0x02;  // Alkaline battery source
        public const int BATTERY_TYPE_NIMH = 0x03;  // Nickel Metal Hydride battery source
        public const int BATTERY_TYPE_UNKNOWN = 0xFF;  // Cannot determine the battery type

        // These are only valid for wireless, connected devices, with known battery types
        // The amount of use time remaining depends on the type of device.
        public const int BATTERY_LEVEL_EMPTY = 0x00;
        public const int BATTERY_LEVEL_LOW = 0x01;
        public const int BATTERY_LEVEL_MEDIUM = 0x02;
        public const int BATTERY_LEVEL_FULL = 0x03;

        // User index definitions
        public const int XUSER_MAX_COUNT = 4;

        public const int XUSER_INDEX_ANY = 0x000000FF;

        //
        // Codes returned for the gamepad keystroke
        //

        public const int VK_PAD_A = 0x5800;
        public const int VK_PAD_B = 0x5801;
        public const int VK_PAD_X = 0x5802;
        public const int VK_PAD_Y = 0x5803;
        public const int VK_PAD_RSHOULDER = 0x5804;
        public const int VK_PAD_LSHOULDER = 0x5805;
        public const int VK_PAD_LTRIGGER = 0x5806;
        public const int VK_PAD_RTRIGGER = 0x5807;

        public const int VK_PAD_DPAD_UP = 0x5810;
        public const int VK_PAD_DPAD_DOWN = 0x5811;
        public const int VK_PAD_DPAD_LEFT = 0x5812;
        public const int VK_PAD_DPAD_RIGHT = 0x5813;
        public const int VK_PAD_START = 0x5814;
        public const int VK_PAD_BACK = 0x5815;
        public const int VK_PAD_LTHUMB_PRESS = 0x5816;
        public const int VK_PAD_RTHUMB_PRESS = 0x5817;

        public const int VK_PAD_LTHUMB_UP = 0x5820;
        public const int VK_PAD_LTHUMB_DOWN = 0x5821;
        public const int VK_PAD_LTHUMB_RIGHT = 0x5822;
        public const int VK_PAD_LTHUMB_LEFT = 0x5823;
        public const int VK_PAD_LTHUMB_UPLEFT = 0x5824;
        public const int VK_PAD_LTHUMB_UPRIGHT = 0x5825;
        public const int VK_PAD_LTHUMB_DOWNRIGHT = 0x5826;
        public const int VK_PAD_LTHUMB_DOWNLEFT = 0x5827;

        public const int VK_PAD_RTHUMB_UP = 0x5830;
        public const int VK_PAD_RTHUMB_DOWN = 0x5831;
        public const int VK_PAD_RTHUMB_RIGHT = 0x5832;
        public const int VK_PAD_RTHUMB_LEFT = 0x5833;
        public const int VK_PAD_RTHUMB_UPLEFT = 0x5834;
        public const int VK_PAD_RTHUMB_UPRIGHT = 0x5835;
        public const int VK_PAD_RTHUMB_DOWNRIGHT = 0x5836;
        public const int VK_PAD_RTHUMB_DOWNLEFT = 0x5837;

        //
        // Flags used in XINPUT_KEYSTROKE
        //
        public const int XINPUT_KEYSTROKE_KEYDOWN = 0x0001;
        public const int XINPUT_KEYSTROKE_KEYUP = 0x0002;
        public const int XINPUT_KEYSTROKE_REPEAT = 0x0004;


        //
        // Structures used by XInput APIs
        //
        struct _XINPUT_GAMEPAD
        {
            public ushort wButtons;
            public byte bLeftTrigger;
            public byte bRightTrigger;
            public short sThumbLX;
            public short sThumbLY;
            public short sThumbRX;
            public short sThumbRY;
        }

        struct _XINPUT_STATE
        {
            public int dwPacketNumber;
            public _XINPUT_GAMEPAD Gamepad;
        }

        struct _XINPUT_VIBRATION
        {
            public ushort wLeftMotorSpeed;
            public ushort wRightMotorSpeed;
        }
        struct _XINPUT_CAPABILITIES
        {
            public byte Type;
            public byte SubType;
            public ushort Flags;
            public _XINPUT_GAMEPAD Gamepad;
            public _XINPUT_VIBRATION Vibration;
        }

        struct _XINPUT_BATTERY_INFORMATION
        {
            public byte BatteryType;
            public byte BatteryLevel;
        }

        struct _XINPUT_KEYSTROKE
        {
            public ushort VirtualKey;
            public ushort Unicode;
            public ushort Flags;
            public byte UserIndex;
            public byte HidCode;
        }

        //
        // XInput APIs
        //
        [DllImport("xinput1_3")]
        extern static int XInputGetState
        (
            int dwUserIndex,  // Index of the gamer associated with the device
            out _XINPUT_STATE pState        // Receives the current state
        );

        [DllImport("xinput1_3")]
        extern static int XInputSetState
        (
            int dwUserIndex,  // Index of the gamer associated with the device
            ref _XINPUT_VIBRATION pVibration    // The vibration information to send to the controller
        );

        [DllImport("xinput1_3")]
        extern static int XInputGetCapabilities
        (
            int dwUserIndex,   // Index of the gamer associated with the device
            int dwFlags,       // Input flags that identify the device type
            out _XINPUT_CAPABILITIES pCapabilities  // Receives the capabilities
        );

        [DllImport("xinput1_3")]
        extern static void XInputEnable
        (
            bool enable     // [in] Indicates whether xinput is enabled or disabled. 
        );

        [DllImport("xinput1_3")]
        extern static int XInputGetDSoundAudioDeviceGuids
        (
            int dwUserIndex,          // Index of the gamer associated with the device
            out Guid pDSoundRenderGuid,    // DSound device ID for render
            out Guid pDSoundCaptureGuid    // DSound device ID for capture
        );

        [DllImport("xinput1_3")]
        extern static int XInputGetBatteryInformation
        (
            int dwUserIndex,        // Index of the gamer associated with the device
            byte devType,            // Which device on this user index
            out _XINPUT_BATTERY_INFORMATION pBatteryInformation // Contains the level and types of batteries
        );

        [DllImport("xinput1_3")]
        extern static int XInputGetKeystroke
        (
            int dwUserIndex,              // Index of the gamer associated with the device
            int dwReserved,               // Reserved for future use
            out      _XINPUT_KEYSTROKE pKeystroke    // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
        );
        #endregion
    }

    //class Xinput
    //{
    //    public Xinput(Game g)
    //    {
    //        game = g;
    //        Connect();
    //    }

    //    Game game;

    //    public void Heartbeat()
    //    {
    //    }

    //    public void Connect()
    //    {
    //        _XINPUT_CAPABILITIES xc;
    //        XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, out xc);
    //        if (xc.Type != XINPUT_DEVTYPE_GAMEPAD)
    //        {
    //            return;
    //        }
    //        if (xc.SubType != XINPUT_DEVSUBTYPE_GAMEPAD)
    //        {
    //            return;
    //        }
    //        if (xc.Flags != XINPUT_CAPS_VOICE_SUPPORTED)
    //        {
    //            return;
    //        }
    //        _XINPUT_VIBRATION xv;
    //        xv.wLeftMotorSpeed = 10000;
    //        xv.wRightMotorSpeed = 10000;
    //        XInputSetState(0, ref xv);
    //    }

    //    #region define
    //    public const int XINPUT_DEVTYPE_GAMEPAD = 0x01;

    //    //
    //    // Device subtypes available in XINPUT_CAPABILITIES
    //    //
    //    public const int XINPUT_DEVSUBTYPE_GAMEPAD = 0x01;

    //    //
    //    // Flags for XINPUT_CAPABILITIES
    //    //
    //    public const int XINPUT_CAPS_VOICE_SUPPORTED = 0x0004;

    //    //
    //    // Constants for gamepad buttons
    //    //
    //    public const int XINPUT_GAMEPAD_DPAD_UP = 0x0001;
    //    public const int XINPUT_GAMEPAD_DPAD_DOWN = 0x0002;
    //    public const int XINPUT_GAMEPAD_DPAD_LEFT = 0x0004;
    //    public const int XINPUT_GAMEPAD_DPAD_RIGHT = 0x0008;
    //    public const int XINPUT_GAMEPAD_START = 0x0010;
    //    public const int XINPUT_GAMEPAD_BACK = 0x0020;
    //    public const int XINPUT_GAMEPAD_LEFT_THUMB = 0x0040;
    //    public const int XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080;
    //    public const int XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100;
    //    public const int XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200;
    //    public const int XINPUT_GAMEPAD_A = 0x1000;
    //    public const int XINPUT_GAMEPAD_B = 0x2000;
    //    public const int XINPUT_GAMEPAD_X = 0x4000;
    //    public const int XINPUT_GAMEPAD_Y = 0x8000;

    //    //
    //    // Gamepad thresholds
    //    //
    //    public const int XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 7849;
    //    public const int XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE = 8689;
    //    public const int XINPUT_GAMEPAD_TRIGGER_THRESHOLD = 30;

    //    //
    //    // Flags to pass to XInputGetCapabilities
    //    //
    //    public const int XINPUT_FLAG_GAMEPAD = 0x00000001;


    //    //
    //    // Structures used by XInput APIs
    //    //
    //    public struct _XINPUT_GAMEPAD
    //    {
    //        public ushort wButtons;
    //        public byte bLeftTrigger;
    //        public byte bRightTrigger;
    //        public short sThumbLX;
    //        public short sThumbLY;
    //        public short sThumbRX;
    //        public short sThumbRY;
    //    }

    //    public struct _XINPUT_STATE
    //    {
    //        public int dwPacketNumber;
    //        public _XINPUT_GAMEPAD Gamepad;
    //    }

    //    public struct _XINPUT_VIBRATION
    //    {
    //        public ushort wLeftMotorSpeed;
    //        public ushort wRightMotorSpeed;
    //    }

    //    public struct _XINPUT_CAPABILITIES
    //    {
    //        public byte Type;
    //        public byte SubType;
    //        public ushort Flags;
    //        public _XINPUT_GAMEPAD Gamepad;
    //        public _XINPUT_VIBRATION Vibration;
    //    }


    //    [DllImport("XInput9_1_0")]
    //    public extern static int XInputGetState
    //    (
    //        int dwUserIndex,  // [in] Index of the gamer associated with the device
    //        out _XINPUT_STATE pState        // [out] Receives the current state
    //    );

    //    [DllImport("XInput9_1_0")]
    //    public extern static int XInputSetState
    //    (
    //        int dwUserIndex,  // [in] Index of the gamer associated with the device
    //        ref _XINPUT_VIBRATION pVibration    // [in, out] The vibration information to send to the controller
    //    );

    //    [DllImport("XInput9_1_0")]
    //    public extern static int XInputGetCapabilities
    //    (
    //        int dwUserIndex,   // [in] Index of the gamer associated with the device
    //        int dwFlags,       // [in] Input flags that identify the device type
    //        out _XINPUT_CAPABILITIES pCapabilities  // [out] Receives the capabilities
    //    );

    //    [DllImport("XInput9_1_0")]
    //    public extern static int XInputGetDSoundAudioDeviceGuids
    //    (
    //        int dwUserIndex,          // [in] Index of the gamer associated with the device
    //        out Guid pDSoundRenderGuid,    // [out] DSound device ID for render
    //        out Guid pDSoundCaptureGuid    // [out] DSound device ID for capture
    //    );

    //    #endregion
    //}
}
